﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JigLibX.Physics;
using JigLibX.Collision;
using Microsoft.Xna.Framework;
using JigLibX.Geometry;
using Microsoft.Xna.Framework.Graphics;
using System.Xml;
using PloobsEngine.SceneControl;
using PloobsEngine.Modelo;
using JigLibX.Math;


namespace PloobsEngine.Physics.XJigLib
{
    public abstract class JigLibXObject : IPhysicObject
    {
        public JigLibXObject()
        {            
        }

        // Local copy of the mass of the object
        float mass = 1;
 
        // The Body managed by the PhysicsObject
        protected Body Body;
        
        private IObject obj;

        protected Vector3 scale = Vector3.One;
 
        // The CollisionSkin managed by the PhysicsObject
        protected CollisionSkin CollisionSkin;
 
        // The mass of the PhysicsObject
        public virtual float Mass
        {
            get { return mass; }
            set {
                // Set the new value
                mass = value;
 
                // Fix transforms
                Vector3 com = SetMass(value);
                if (CollisionSkin != null)
                    CollisionSkin.ApplyLocalTransform(
                        new JigLibX.Math.Transform(-com, Matrix.Identity));
            }
        }

        public virtual Vector3 Position
        {
            get { return Body.Position; }
            set { Body.MoveTo(value, Body.Orientation); }
        }

        public Vector3 EulerRotation
        {
            get
            {
                Quaternion q = Quaternion.CreateFromRotationMatrix(Rotation);
                return new Vector3(q.X, q.Y, q.Z);
            }
            set 
            {
                Rotation = Matrix.CreateFromYawPitchRoll(value.Y, value.X, value.Z); 
            }
        }


        // Override the rotation of the base class to that
        // of the physics object
        public  virtual Matrix Rotation
        {
            get { return Body.Orientation; }
            set { JiggleMath.Orthonormalise(ref value); Body.SetOrientation(value); }
         
        }

 
        // The PhysicsObject's rotation
        //public Vector3 Rotation
        //{
        //    get {
        //        Quaternion q = Quaternion.CreateFromRotationMatrix(Orientation);
        //        return new Vector3(q.X, q.Y, q.Z);
        //    }
        //    set { Body.MoveTo(Body.Position, Matrix.CreateFromYawPitchRoll(
        //        MathHelper.ToRadians(value.Y),
        //        MathHelper.ToRadians(value.X),
        //        MathHelper.ToRadians(value.Z)));
        //    }
        //}
 
        // Override the BoundingBox of the base class to that
        // of the physics object
        public virtual  BoundingBox BoundingBox
        {
             get
            {
                if (Body.CollisionSkin != null)
                    return Body.CollisionSkin.WorldBoundingBox;
                else
                    return new BoundingBox(Position - Vector3.One,
                        Position + Vector3.One);
            
            }
        }
        // The body's velocity
        public virtual Vector3 Velocity
        {
            get { return Body.Velocity; }
            set { Body.Velocity = value; }
        } 
        
 
        // Sets the mass of the PhysicsObject
        public virtual Vector3 SetMass(float mass)
        {
            PrimitiveProperties primitiveProperties =
                new PrimitiveProperties(
                    PrimitiveProperties.MassDistributionEnum.Solid,
                    PrimitiveProperties.MassTypeEnum.Density, mass);
 
            float junk; Vector3 com; Matrix it, itCoM;
 
            CollisionSkin.GetMassProperties(primitiveProperties,
                out junk, out com, out it, out itCoM);
            Body.BodyInertia = itCoM;
            Body.Mass = junk;
 
            return com;
        }
 
        // Rotates and moves the model relative to the physics object to
        // better align the model with the object
        public virtual void OffsetModel(Vector3 PositionOffset,
            Matrix RotationOffset)
        {
            CollisionSkin.ApplyLocalTransform(
                new JigLibX.Math.Transform(PositionOffset, RotationOffset));
        }



        #region IPhysicObject Members

        public virtual Matrix WorldMatrix
        {
            get
            {
              return   Matrix.CreateScale(Scale) *  Rotation *  Matrix.CreateTranslation(Position);
            }
            
        }

        #endregion

        #region IPhysicObject Members


        public virtual Vector3 Scale
        {
            get
            {
                return scale;
            }
            set
            {
                scale = value;
            }
        }

        public Body Body_
        {
            get
            {
                return Body;
            }
        }
        public CollisionSkin CollisionSkin_
        {
            get
            {
                return CollisionSkin;
            }
        }

        public virtual void SetImobile()
        {

            Body.Immovable = true;

        }

        public virtual void EnableBody()
        {
            Body.EnableBody();
        }
        public virtual void DisableBody()
        {
            Body.DisableBody();
        }

        public abstract void Serialize(XmlTextWriter writer);
        public abstract void DeSerialize(XmlNode node, EngineStuff engine, IModelo world, Vector3 position, Matrix rotation);

        
        #region IPhysicObject Members


        public virtual bool isMotionLess
        {
            get { return Body.Immovable; }
            set { Body.Immovable = value; }
        }

        #endregion


        IObject IPhysicObject.ObjectOwner
        {
            get
            {
                return this.obj;
            }
            set
            {
                this.obj  = value;
            }
        }

        #endregion

        
        #region IPhysicObject Members


        public virtual Vector3 FaceVector
        {
            get
            {
                return Vector3.Transform(Vector3.UnitZ, Rotation);                
                //return this.Velocity / this.Velocity.Length();
            }
            
        }

        #endregion

        #region IPhysicObject Members

        public abstract PhysicObjectTypes PhysicObjectTypes{get;}        
        #endregion

        #region IPhysicObject Members


        public void Enable()
        {            
            this.EnableBody();
        }

        public void Disable()
        {
            
            this.DisableBody();            
        }

        #endregion

        #region IPhysicObject Members


        public void ApplyImpulse(Vector3 force)
        {
            if (!Body.IsActive)
                Body.SetActive();
            if (force != Vector3.Zero) 
            Body.ApplyWorldImpulse(force);                        
        }

        //public void ApplyTorque(Vector3 torque)
        //{
        //    if (!Body.IsActive)
        //        Body.SetActive();
        //    if (torque != Vector3.Zero)
        //        Body.AddWorldTorque(torque);                        
        //}

        #endregion

        #region IPhysicObject Members


        public void ApplyTorque(Vector3 force)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}


